//
//	File Name   :	Image.cpp
//	Description :	Image implementation file.
//	Author		:	William McVicar
//  Mail		:	mcvicar.william@gmail.com
//

//  Precompiled Header
#include "CommonDefines.h"

//  Library Includes

//  Local Includes
#include "ProteinFramework.h"
#include "IFileSystem.h"
#include "loaders/ddsloader.h"
#include "loaders/bmpLoader.h"
#include "loaders/tgaLoader.h"

//  This includes
#include "Image.h"

//	Macros

//  Static Variables
static const c8* DDS_EXTENSION = ".dds";
static const c8* BMP_EXTENSION = ".bmp";
static const c8* TGA_EXTENSION = ".tga";

//  Static Function Prototypes

//  Implementation

namespace Protein
{

Image::Image()
{
	//
}

Image::~Image()
{

}

void Image::Init(u32 _width, u32 _height, u32 _depth, ePixelFormat _format, u32 _mipMapCount, const std::string& _path, byte* _data, u32 _datasize )
{
	m_uiWidth		= _width;
	m_uiHeight		= _height;
	m_uiDepth		= _depth;
	m_uiDataSize	= _datasize;
	m_ePixelFormat	= _format;
	m_uiMipMapCount = _mipMapCount;
	m_imagePath		= _path;

	m_pData			= new byte[ _datasize ];
	memcpy( &m_pData[0], _data, _datasize );
}

int Image::GetMipMappedSize(const i32 firstMipMapLevel, i32 nMipMapLevels ) const 
{
	int w = Width (firstMipMapLevel);
	int h = Height(firstMipMapLevel);
	int d = Depth (firstMipMapLevel);
	
	int size = 0;
	bool compressed = isCompressedFormat(m_ePixelFormat);
	while (nMipMapLevels)
	{
		if( compressed )
			size += ((w + 3) >> 2) * ((h + 3) >> 2) * d;
		else 
			size += w * h * d;
		
		w >>= 1;
		h >>= 1;
		d >>= 1;
		if (w + h + d == 0) break;
		if (w == 0) w = 1;
		if (h == 0) h = 1;
		if (d == 0) d = 1;

		--nMipMapLevels;
	}

	if ( compressed )
		size *= getBytesPerBlock(m_ePixelFormat);
	else 
		size *= getBytesPerPixel(m_ePixelFormat);

	return (m_uiDepth == 0)? 6 * size : size;
}

u32 Image::getImageDataSize(u32 width, u32 height, u32 depth, ePixelFormat pixelFormat )
{
    u32 dataSize = 0;

	for (u32 i = 0; i < m_uiMipMapCount; i++)
    {
        u32 w = width, h = height;

        if (!Image::isCompressedFormat(pixelFormat))
			dataSize += w * h * depth * Image::getBytesPerPixel(pixelFormat);
        else
        {
            u32 compressionBlockWidth  = 4;
            u32 compressionBlockHeight = 4;

            u32 xBlocks = ( w + compressionBlockWidth  - 1) / compressionBlockWidth;
            u32 yBlocks = ( h + compressionBlockHeight - 1) / compressionBlockHeight;

			u32 size = xBlocks * yBlocks * depth * getBytesPerBlock(pixelFormat);

            dataSize += size;
        }

        getNextMipmapSize(width, height, depth);
    }

    return dataSize;
}

bool Image::load( const char* szFilename )
{
	eImageFormat format;
	std::string strPath = szFilename;
	std::string extension = strPath.substr( strPath.find_last_of("."), strPath.length() );
	strPath = strPath.substr( 0, strPath.find_last_of(".") );
	if( strcmp( DDS_EXTENSION, extension.c_str() ) == 0 )
		format = IF_DDS;
	else if( strcmp( BMP_EXTENSION, extension.c_str() ) == 0 )
		format = IF_BMP;
	else if( strcmp( TGA_EXTENSION, extension.c_str() ) == 0 )
		format = IF_TGA;
	else
		format = IF_UNSUPPORTED;

	if( format == IF_UNSUPPORTED )
		return false;	//unknown format of file is corrupted

	if( format == IF_DDS )
		return CDDS::Load( strPath.c_str(), *this );

	if( format == IF_BMP )
		return CBMP::Load( strPath.c_str(), *this );

	if( format == IF_TGA )
		return CTGA::Load( strPath.c_str(), *this );

	return false;
}

void Image::clear()
{
	delete [] m_pData;

	m_uiWidth		= 0;
	m_uiHeight		= 0;
	m_uiDepth		= 0;
	m_uiDataSize	= 0;
	m_ePixelFormat	= PF_UNKNOWN;
	m_uiMipMapCount = 0;
	m_imagePath		= "";
	m_pData			= NULL;
}

}